/* 地图画图工具 */
import * as turf from '@turf/turf'
/*
@获取相交的网格的不同区域
@param polygon1 第一个网格
@param polygon2 第二个网格
@return 差异区域网格
*/
export const getDifference = (polygon1, polygon2) => {
  const polygon = turf.difference(turf.polygon([getCoords(polygon1)]), turf.polygon([getCoords(polygon2)]))
  return polygon ? polygon.geometry.coordinates[0] : []
}
/*
@获取相交的网格的相同区域
@param polygon1
@param polygon2
@return 相交区域网格
*/
export const getIntersect = (polygon1, polygon2) => {
  const polygon = turf.intersect(turf.polygon([getCoords(polygon1)]), turf.polygon([getCoords(polygon2)]))
  return polygon ? polygon.geometry.coordinates[0] : []
}
/*
@面是否相交
@prarm polygon [{lng:'',lat:''}...]
@return 是否相交 Boolean
*/
export const booleanOverlap = (polygon1, polygon2) => {
  const crosses = turf.booleanOverlap(turf.polygon([getCoords(polygon1)]), turf.polygon([getCoords(polygon2)]))
  return crosses
}
/*
@网格坐标格式处理
@params polygon
@return coords
*/
const getCoords = polygon => {
  const coords = polygon.map(point => [Number(parseFloat(point.lng).toFixed(6)), Number(parseFloat(point.lat).toFixed(6))])
  return coords
}
/*
@按照网格区域大小排序
@params []
@return []
*/
export const sortByPloygonArea = (polygons, type = 'location') => {
  // 冒泡排序将最大网格放在第一个
  let temp
  for (let i = 0; i < polygons.length - 1; i++) {
    for (let j = i + 1; j < polygons.length; j++) {
      if (turf.area(turf.polygon([getCoords(polygons[i][type].polygon)])) < turf.area(turf.polygon([getCoords(polygons[j][type].polygon)]))) {
        temp = polygons[j]
        polygons[j] = polygons[i]
        polygons[i] = temp
      }
    }
  }
  return polygons
}
/*
@获取网格中心点（质心）
@prarm polygon [{lon:'',lat:''}...]
@return centerPoint { lng:'',lat:'' }
*/
export const getCenterPoint = polygonPointArray => {
  let centerPoint = turf.centerOfMass(
    turf.polygon([
      polygonPointArray.map(v => {
        return [+v.lon, +v.lat]
      })
    ])
  ).geometry.coordinates
  centerPoint = new MapCore.Point(centerPoint)
  return centerPoint
}

/*
@给网格添加label
@prarm polygonPointArray [{lon:'',lat:''}...]
@prarm html 显示数据
@prarm style 显示样式
*/
export const setPolygonLabel = (polygonPointArray, html, style) => {
  const centerPoint = getCenterPoint(polygonPointArray)
  const label = new MapCore.MyLabel(html, {
    position: centerPoint
  })
  style = style || {
    color: '#fff', // 字体颜色
    fontSize: '12px', // 字体大小
    fontFamily: '微软雅黑', // 字体族
    backgroundColor: 'var(--color-primary)', // 背景色
    border: `1px solid var(--color-primary)`, // 边框大小
    borderRadius: '10px',
    padding: '2px 6px',
    transform: 'translate(-50px, -15px)'
  }
  label.setStyle(style)
  return label
}

/*
@网格点去重，然后首尾相连
@polygon [{lng:'',lat:''}...]
*/
export const getConnectPath = polygon => {
  const arr = polygon.map(point => `${Number(parseFloat(point.lng).toFixed(6))},${Number(parseFloat(point.lat).toFixed(6))}`)
  let location = [...new Set(arr)]
  location = location.map(item => {
    return {
      lng: item.split(',')[0],
      lat: item.split(',')[1]
    }
  })
  location.push(location[0])
  return location
}
/*
@裁剪网格
@poly 需要裁剪的面  [{lng:'',lat:''}...]
@splitter 裁剪范围 [['',''],['','']...]
*/
export const polygonSlice = (poly, splitter) => {
  poly = turf.getGeom(turf.polygon([getCoords(poly)]))
  splitter = turf.getGeom(turf.lineString(splitter))
  // 获取裁剪线
  const line = trimStartEndPoints(poly, splitter)
  if (line == null) return turf.featureCollection([poly])
  const newPolygons = []
  let cutDone = false
  const upperCut = cutPolygon(poly, line, 1, 'upper')
  const lowerCut = cutPolygon(poly, line, -1, 'lower')
  if (upperCut != null && lowerCut != null) {
    cutDone = true
  }
  if (cutDone) {
    newPolygons.push(upperCut.geometry)
    newPolygons.push(lowerCut.geometry)
  } else {
    newPolygons.push(poly)
  }
  const generatedPolygons = []
  newPolygons.forEach(polyg => {
    if (polyg.type === 'Polygon') {
      generatedPolygons.push(polyg)
    }

    if (polyg.type === 'MultiPolygon') {
      polyg.coordinates.forEach((p) => {
        generatedPolygons.push(turf.polygon([p[0]]).geometry)
      })
    }
  })
  const features = generatedPolygons.map(v => v.coordinates[0])
  // 冒泡排序将最大网格放在第一个
  let temp
  for (let i = 0; i < features.length - 1; i++) {
    for (let j = i + 1; j < features.length; j++) {
      if (turf.area(turf.polygon([features[i]])) < turf.area(turf.polygon([features[j]]))) {
        temp = features[j]
        features[j] = features[i]
        features[i] = temp
      }
    }
  }
  return turf.featureCollection(features)
}
/*
取面内的裁剪起始点和终点
*/
const trimStartEndPoints = (poly, line) => {
  let startAt = 0
  let endAt = line.coordinates.length
  for (let j = 0; j < line.coordinates.length; j++) {
    if (turf.booleanPointInPolygon(turf.point(line.coordinates[j]), poly)) {
      startAt++
    } else {
      break
    }
  }
  for (let j = line.coordinates.length - 1; j >= 0; j--) {
    if (turf.booleanPointInPolygon(turf.point(line.coordinates[j]), poly)) {
      endAt--
    } else {
      break
    }
  }
  line.coordinates = line.coordinates.slice(startAt, endAt)
  return line.coordinates.length > 1 ? line : null
}

/**
@根据线裁剪面
*/
const cutPolygon = (poly, line, direction, id) => {
  const cutPolyGeoms = []
  let retVal = null
  if (poly.type !== 'Polygon' || line.type !== 'LineString') return retVal
  const intersectPoints = turf.lineIntersect(poly, line)
  const nPoints = intersectPoints.features.length
  if (nPoints === 0 || nPoints % 2 !== 0) return retVal
  const thickLinePolygon = prepareDiffLinePolygon(line, direction)
  let clipped
  try {
    clipped = turf.difference(poly, thickLinePolygon)
  } catch (e) {
    return retVal
  }
  if (clipped.geometry.type === 'MultiPolygon') {
    for (let j = 0; j < clipped.geometry.coordinates.length; j++) {
      const polyg = turf.polygon(clipped.geometry.coordinates[j])
      const overlap = turf.lineOverlap(polyg, line, { tolerance: 0.005 })

      if (overlap.features.length > 0) {
        cutPolyGeoms.push(polyg.geometry.coordinates)
      }
    }
  } else {
    const polyg = turf.polygon(clipped.geometry.coordinates)
    const overlap = turf.lineOverlap(polyg, line, { tolerance: 0.005 })
    if (overlap.features.length > 0) {
      cutPolyGeoms.push(polyg.geometry.coordinates)
    }
  }
  if (cutPolyGeoms.length === 1) {
    retVal = turf.polygon(cutPolyGeoms[0], { id: id })
  } else if (cutPolyGeoms.length > 1) {
    retVal = turf.multiPolygon(cutPolyGeoms, { id: id })
  }
  return retVal
}

const prepareDiffLinePolygon = (line, direction) => {
  let offsetLine
  let polyCoords = []
  let thickLinePolygon
  const offsetScales = [0.01, 0.001, 0.0001]
  for (let j = 0; j < offsetScales.length; j++) {
    polyCoords = []
    offsetLine = turf.lineOffset(line, offsetScales[j] * direction, {
      units: 'kilometers'
    })
    for (let k = 0; k < line.coordinates.length; k++) {
      polyCoords.push(line.coordinates[k])
    }
    for (let k = offsetLine.geometry.coordinates.length - 1; k >= 0; k--) {
      polyCoords.push(offsetLine.geometry.coordinates[k])
    }
    polyCoords.push(line.coordinates[0])
    const thickLineString = turf.lineString(polyCoords)
    thickLinePolygon = turf.lineToPolygon(thickLineString)
    const result = turf.unkinkPolygon(thickLinePolygon)
    const selfIntersectPolygons = result.features.length
    if (selfIntersectPolygons === 1) {
      return thickLinePolygon
    }
  }
  return thickLinePolygon
}

/**
 * @合并多边形 polygons Array
 * all 是否返回所有合并结果
 */
export const polygonsUnion = (polygons, all) => {
  polygons = polygons.map(v => turf.polygon([getCoords(v)]))
  const union = polygons.reduce((prev, cur, idx) => {
    // 处理第一次的空数组
    if (idx === 0) return cur
    // 如果需要返回多个结果 则不执行判断相交操作
    if (!all) {
      // 判断合并的网格是否相交
      const iscross = turf.booleanOverlap(prev, cur)
      // 不相交则比对下一个
      if (!iscross) return prev
    }
    return turf.union(prev, cur)
  }, {})
  // 返回全部合并区域
  if (all) return union.geometry.coordinates
  // 取最大范围返回
  const bb = union.geometry.coordinates
  let n = 0
  let max = 0
  for (let b = 0; b < bb.length; b++) {
    const area = turf.area(turf.polygon([bb[b]]))
    if (area > max) {
      max = area
      n = b
    }
  }
  const maxArea = union.geometry.coordinates[n]
  return maxArea
}
